package rmi.loadtest;

import java.io.IOException;
import java.net.ConnectException;
import java.net.UnknownHostException;
import java.rmi.NoSuchObjectException;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import java.util.Date;
import java.util.NoSuchElementException;
import java.util.Scanner;

import org.apache.log4j.Logger;



import rmi.analytics.server.AnalyticsInterface;

import rmi.domain.RegistrySingleton;
import rmi.domain.RemoteClientInterface;
import rmi.management.client.ManagementClient;


public class LoadTest {
	public static Logger log = Logger.getLogger(LoadTest.class);
	
	private static int clients;
	private static  int auctionsPerMin;
	private static  int auctionDuration;
	private static  int updateIntervalSec;
	private static  int bidsPerMin;
	
	private static ArrayList<TestClientThread> testClients = new ArrayList<TestClientThread>();
	private static ManagementClient mc;
	public static int auction =0;
	
	public LoadTest() {
		
	}

	/*
	 * Testing component to test the scalability and reliability of the program
	 * @param host, tcpport, analytics.bindingName
	 */
	public static void main(String[] args) throws Exception{
		//parameter
		String host = "";
		String tcpport ="";
		String analyticsBindingName = "";
		
		//check parameters
		if (args.length==3){
			host = args[0];
			tcpport = args[1];
			analyticsBindingName = args[2];
		}
		
		boolean resume=true;
		LoadTest test = new LoadTest();			
		boolean chkprop = test.loadProperties();
		
		//if the parameters are ok, a ManagementClient will be created and a reference from the AnalyticServer is looked up from the registry
		if (chkparam(host, tcpport, analyticsBindingName) && chkprop){
			
			//Management Client
			 Registry reg = RegistrySingleton.initialRegistry();
			 mc = new ManagementClient();
			 //set auto mode
			 mc.setMode(true);
			 try{
				 //lookup for the AnalyticsServer in the registry
	            AnalyticsInterface anServ =(AnalyticsInterface) reg.lookup(analyticsBindingName);
	            RemoteClientInterface stub = (RemoteClientInterface) UnicastRemoteObject.exportObject(mc,0);
	            anServ.subscribe( ".*", stub);	            
			  } catch (RemoteException e) {
				  log.error("Error: AnalyticsServer is not available");
				  clients = 0; 
				  resume=false;
				  log.info("Close LoadTest");
			  } catch (NotBoundException e) {
			      log.error("Error: AnalyticsServer is not available");
			      clients = 0;
			      resume=false;
			      log.info("Close LoadTest");
			  }		 		
			 
			//start threads for a given number of bidding clients from the porperties file
			int c = 0;
			Date startTime = new Date(); //starttime of the LoadTest
			TestClientThread thread;
			while (c < clients ) //number of clients is the number of iterations
			{
				try {
					thread = new TestClientThread(tcpport,host,auctionsPerMin, auctionDuration, updateIntervalSec,bidsPerMin,startTime);
					//saving testclients to shut down later
					synchronized (testClients) {
						testClients.add(thread);
					}
					thread.start();				
					c++;
				}
				catch(ConnectException ex){
					//if server is not available, shutdown
					log.info("Server '"+host+"' on port '"+tcpport+"' is not available!");
					resume = false;
					shutdown();
					break;
					
				} catch (UnknownHostException e) {	
					resume = false;
					shutdown();
					break;
				} catch (IOException e) {
					resume = false;
					shutdown();
					break;
				}				
			}		
			Scanner scanner = new Scanner(System.in);
		    String input = "";
			   
		    //listens for a shutdown event
			while(resume){
				System.out.print(">");
				try{
					input = scanner.nextLine();
				}catch (NoSuchElementException e){
					log.debug(e.getMessage());
				}
				if(input.equals("!end")||input.equals("")||input.equals("!exit")){//shutdown					
					resume=false;	 					
					shutdown();					
					//close scanner
					scanner.close();      					
					System.out.println("Shutting down LoadTest!");
				}			
			}			
			
		}
		else{
			if(chkprop) //wrong Usage entered
				System.out.println("Usage: Java Client <server.host> <server.port> <analytics.bindingName>");//Usage
			else
				System.out.println("There are not valid values in loadtest.properties");
		}
		
	}
	
	private static void shutdown() {
		//stop test clients
		synchronized (testClients) {		        		
			for (TestClientThread t : testClients) {	        					
				t.setStop(true);
			}		        			
		}
		//unexport ManagementClient
		try {
			UnicastRemoteObject.unexportObject(mc, true);
		} catch (NoSuchObjectException e) {
			log.error("Client was not exportet");
		}		
	}

	//check parameters
	public static boolean chkparam(String host, String tcpport, String analyticsBindingName){
		if (host.equals("")||tcpport.equals("")||analyticsBindingName.equals("")){
			return false;
		}
		try{
			int i = Integer.parseInt(tcpport);
			
		}
		catch(NumberFormatException e){
			return false;
		}
		return true;
		
	}
	
	//read load.properties
		public boolean loadProperties(){
			
			java.io.InputStream is = ClassLoader.getSystemResourceAsStream("loadtest.properties");
			if (is != null) {
				java.util.Properties props = new java.util.Properties();
			try {
				props.load(is);
				
				clients=Integer.parseInt(props.getProperty("clients"));
				auctionsPerMin = Integer.parseInt(props.getProperty("auctionsPerMin"));
				auctionDuration=Integer.parseInt(props.getProperty("auctionDuration"));
				updateIntervalSec=Integer.parseInt(props.getProperty("updateIntervalSec"));
				bidsPerMin=Integer.parseInt(props.getProperty("bidsPerMin"));		
				
				
			} catch (IOException e) {
			
				e.printStackTrace();
			}
			catch(NumberFormatException e){
				return false;
			}
			
			finally {
				try {
					is.close();
				} catch (IOException e) {
					
					e.printStackTrace();
				}
			}
			} else {
				log.error("Properties file not found!");
			}
			
			return true;

		}
}
